﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Faml.Frontend
{
    /// <summary>
    /// FamlReferenceExpression is used as reference to a FamlExpressionContainer instance by the optimizer
    /// </summary>
    public class FamlReferenceExpression : FamlExpression
    {
        private FamlExpressionContainer container;

        public FamlReferenceExpression(FamlExpressionContainer container)
        {
            this.container = container;
            MakeMetadata();
        }

        public FamlReferenceExpression(FamlExpression expression) 
            : this(new FamlExpressionContainer(expression))
        {
        }

        /// <summary>
        /// Gets the container this object is referenced to.
        /// </summary>
        public FamlExpressionContainer ReferencedContainer
        {
            get { return container; }
        }

        public override FamlExpression Expand()
        {
            throw new NotImplementedException();
        }

        protected override Type ComputeType()
        {
            return container.Expression.Type;
        }

        protected override void MakeMetadata()
        {
            this.metadata = container.Expression.Metadata;
        }

        public override FamlExpressionType NodeType
        {
            get { return FamlExpressionType.ExpressionReference; }
        }

        public override IEnumerable<FamlExpression> Children
        {
            get { yield break; }
        }

        public override string ToString()
        {
            if (container.Name == null)
                return String.Format("~\\[{0}]", container.Expression);
            else
                return " " + container.Name + " ";
        }
    }

    public class FamlExpressionContainer
    {
        private FamlExpression expression;
        private object value;
        private string name = null;

        public FamlExpressionContainer(FamlExpression expression)
        {
            this.expression = expression;
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Gets or sets a result of evaluation of the inner expression.
        /// </summary>
        public object Value
        {
            get {
                if (value == null)
                    throw new ApplicationException(this.ToString() + " is not evaluated yet");
                return value; 
            }
            set { this.value = value; }
        }

        /// <summary>
        /// Gets or sets an expression that is the container's content.
        /// </summary>
        public FamlExpression Expression
        {
            get { return expression; }
            set { expression = value; }
        }

        public override string ToString()
        {
            return String.Format("Container [{0}]", expression);
        }
    }
}
